import os
import numpy as np

class func(object):
    def __init__(self, arity):
        self.arity = arity


program = [
    func(2),
    1,
    func(2),
    func(2),
    1,
    2,
]

program = [
    func(3),
    func(2),
    func(2),
    1,
    2,
    3,
]


program_reverse = list(reversed(program))

program_reverse_arity = [val_func.arity for val_func in program_reverse if isinstance(val_func, func)]
program_reverse_pos = [i for i in range(len(program_reverse)) if isinstance(program_reverse[i], func)]
program_reverse_pos = np.array(program_reverse_pos)

cum_arity = np.array(program_reverse_arity)
cum_arity = cum_arity.cumsum()

difference = cum_arity - program_reverse_pos

program_reverse_pos = program_reverse_pos[difference >= 1]
pick = program_reverse[program_reverse_pos[0]]

print(program)
print(pick)

#
#
# for n, val_func in enumerate(program_reverse):
#     # example
#     # n=0, val_func=59
#     # n=1, val_func=<gplearn_evolve.functions._Function object at 0x000001AE894F9E48>
#     if isinstance(val_func, (int, float, np.float32, np.float64)):
#         # TODO - 变量不处理
#         pass
#     elif isinstance(val_func, func):
#         # TODO - 只返回函数
#         # TODO - val_func.arity < n 表示只是访问到子结点
#         if val_func.arity <= n:
#             if n + 1 < len(program_reverse):
#                 # not root unit but arity<=n, then pop
#                 program_reverse[n] = 1
#                 for i_arity in range(val_func.arity):
#                     # alist = [1, 2, 3]
#                     # alist.pop(0) => alist = [2, 3] 去掉第一个元素
#                     program_reverse.pop(0)
#                 break
#             else:
#                 # TODO - if n is root, return root func (top root 一定是函数)
#                 return val_func
#         else:
#             # TODO - if func's arity == n, then return func
#             return val_func

''''''
###
program_apply = [func(2),
func(2),
func(2), 12, 7,
func(2), 6, 0.829, 0.785]

apply_stack = []
for node in program_apply:
    if isinstance(node, func):
        apply_stack.append([node])
    else:
        # Lazily evaluate later
        apply_stack[-1].append(node)

while len(apply_stack[-1]) == apply_stack[-1][0].arity + 1:
    # Apply functions that have sufficient arguments
    function = apply_stack[-1][0]

    print(function)
